#ifndef __INTEGER_HPP__
#define __INTEGER_HPP__

#include <gmp.h>

#include "Block.hpp"


/**
 * implements arbitrarily long integers and provides functions for performing calculations
 * (wrapper for GMP library)
 */
class Integer {

	private:
		mpz_t value;
		static gmp_randstate_t randState;
		static bool randomInited;

	public:
		// {{{ Constructors
		Integer();
		Integer(unsigned long int value);
		Integer(const Integer &other);
		Integer(const Block &dataBlock);
		// }}}

		// {{{ Assignment Operators
		Integer& operator=(unsigned long int value);
		Integer& operator=(const Integer &other);
		// }}}

		// {{{ Operators +, -, *, /
		Integer operator+(const Integer &other);
		Integer operator+(unsigned long int value);
		Integer& operator+=(const Integer &other);
		Integer& operator+=(unsigned long int value);
		Integer operator-(const Integer &other);
		Integer operator-(unsigned long int value);
		Integer& operator-=(const Integer &other);
		Integer& operator-=(unsigned long int value);
		Integer operator*(const Integer &other);
		Integer operator*(unsigned long int value);
		Integer& operator*=(const Integer &other);
		Integer& operator*=(unsigned long int value);
		Integer operator/(const Integer &other);
		Integer operator/(unsigned long int value);
		Integer& operator/=(const Integer &other);
		Integer& operator/=(unsigned long int value);
		// }}}

		// {{{ operators < > == !=
		bool operator<(const Integer &other);
		bool operator<=(const Integer &other);
		bool operator>(const Integer &other);
		bool operator>=(const Integer &other);
		bool operator==(const Integer &other);
		bool operator!=(const Integer &other);
		bool operator<(unsigned long int other);
		bool operator<=(unsigned long int other);
		bool operator>(unsigned long int other);
		bool operator>=(unsigned long int other);
		bool operator==(unsigned long int other);
		bool operator!=(unsigned long int other);
		// }}}

		// {{{ Useful mathematical functions
		/**
		 * The Miller Rabin prime test is a probabilistic prime number test;
		 * It will return "true" if the number might be prime (p = 0.75) and "false" if it is definitely no prime.
		 */
		bool millerRabinMightBePrime(const int repetitions) const;

		/**
		 * calculates the power of current integer in modular ring
		 * @param exponent
		 * @param Modulo size of modular ring
		 */
		Integer &powMod(const Integer &Exponent, const Integer &Modulo);

		/**
		 * calculates greatest common divisor of parameters a and b
		 * @param a
		 * @param b
		 * @param g contains result
		 */
		static void gcd(Integer &g, const Integer &a, const Integer &b);

		/**
		 * calculates extended euclid of given integers a and b
		 * g = gcd(a, b)
		 * a * s  +  b * t  =  g
		 */
		static void extendedGcd(Integer &g, Integer &s, Integer &t, const Integer &a, const Integer &b);

		/**
		 * randomizes this integer in range of 0 .. 2^(bits-1)
		 */
		void randomize(unsigned int bits);
		// }}}

		// {{{ Internal functions, destructor
		static void randomInit();
		~Integer();
		// }}}

		// {{{ Input/Output functions
		void dump() const;
		void writeToFile(FILE *f) const;
		void readFromFile(FILE *f);
		unsigned long int getValue() const;
		Block toBlock() const;
		// }}}

};

#endif

